package com.zhouyer.study.server;

import com.zhouyer.study.classloader.MyClassLoader;
import com.zhouyer.study.servlet.HttpServlet;
import com.zhouyer.study.utils.HttpProtocolUtil;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;

import javax.xml.parsers.SAXParser;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * 迷你版Tomcat 启动类
 *
 * @author zhouyao
 * @version 1.0
 * @date 2021/9/14 8:49 上午
 */
public class Bootstrap {
    /**
     * 定义socket监听的端口号
     */
    private int port = 8080;

    private Mapper mapper = new Mapper();

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    /**
     * MyMinicat启动需要初始化展开的⼀些操作
     */
    public void start() throws Exception {
        //加载解析server.xml
        loadServerConfig();

        int corePoolSize = 10;
        int maximumPoolSize = 50;
        long keepAliveTime = 100L;
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(50);
        ThreadFactory threadFactory = Executors.defaultThreadFactory();
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        //定义一个线程池
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);

        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("=========>MyMinicat start on port:" + port);

        /*********** MyMinicat多线程改造，使用线程池 ****************/
        while (true) {
            System.out.println("=======>使用线程池");
            Socket socket = serverSocket.accept();
            threadPoolExecutor.execute(new RequestProcessor(socket, mapper));
        }
    }

    private void loadServerConfig() {
        InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream("server.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document doc = saxReader.read(resourceAsStream);
            Element rootElement = doc.getRootElement();
            // 设置端口号
            Element connectorElement = (Element) rootElement.selectSingleNode("/Server/Service/Connector");
            String port = connectorElement.attributeValue("port");
            setPort(Integer.valueOf(port));
            List<Element> hostElList = rootElement.selectNodes("//Host");
            for (Element hostEl : hostElList) {
                Host host = new Host();
                // 主机
                String hostName = hostEl.attributeValue("name");
                // webapp的绝对路径
                String appBase = hostEl.attributeValue("appBase");
                //遍历webapp的路径下的文件，每一个文件就是一个应用
                File appBaseFile = new File(appBase);
                File[] files = appBaseFile.listFiles();
                for (File file : files) {
                    // 每一个目录就表示一个应用，就一个上下文Context
                    Context context = new Context();
                    context.setAppContext(file.getName());

                    // 加载并解析该应用对应的web.xml,并初始化Wrapper,即一个wrapper对应一个Servlet
                    File webXmlFile = new File(file, "web.xml");
                    List<Wrapper> wrappers = loadWebXml(webXmlFile.getAbsolutePath());
                    context.setWrapperList(wrappers);
                    host.getContexts().add(context);
                }
                host.setName(hostName);
                mapper.getHosts().add(host);
            }
        } catch (DocumentException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解析web.xml,初始化Servlet,并封装Wrapper对象
     *
     * @return void
     * @author zhouyao
     * @date 2021/9/14 2:38 下午
     */
    private List<Wrapper> loadWebXml(String absolutePath) {
        List<Wrapper> wrappers = new ArrayList<>(10);
        SAXReader saxReader = new SAXReader();
        try {
            MyClassLoader myClassLoader = new MyClassLoader();
            Document document = saxReader.read(absolutePath);
            Element rootElement = document.getRootElement();
            List<Element> selectNodes = rootElement.selectNodes("//servlet");
            for (Element element : selectNodes) {
                Wrapper wrapper = new Wrapper();
                // <servlet-name>myServlet</servlet-name>
                String servletName = element.selectSingleNode("servlet-name").getStringValue();
                // <servlet-class>com.zhouyer.study.servlet.MyServlet</servlet-class>
                String servletClass = element.selectSingleNode("servlet-class").getStringValue();

                // 根据servlet-name的值，找到url-pattern
                Element servletMapping = (Element) rootElement.selectSingleNode(String.format("/web-app/servlet-mapping[servlet-name='%s']", servletName));
                String urlPattern = servletMapping.selectSingleNode("url-pattern").getStringValue();
                wrapper.setUrlPattern(urlPattern);
                wrapper.setServlet((HttpServlet) myClassLoader.findClass(absolutePath.replace("web.xml", "") + servletClass).newInstance());
                wrappers.add(wrapper);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return wrappers;
    }

    /**
     * MyMinicat 程序的启动入口
     *
     * @author zhouyao
     * @date 2021/9/14 8:53 上午
     */
    public static void main(String[] args) throws Exception {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.start();
    }
}
